import { NextRequest } from "next/server";
import { logError, logSpecial } from "../io/log";
import Joi from 'joi'
import { ResCode, RejectData } from "./code";
import JWT from "../jwt";
// import { RightsManagement } from "@/types/database/user";
import 'server-only'//代表仅服务端可使用
// import { ModuleType } from "@/types/other";
/**获取query参数 */
export const getQuery = <T extends Record<string, any>>(req: NextRequest) => {
    const query: Record<string, any> = {};
    req.nextUrl.searchParams.forEach((value, key) => {
        query[key] = value;
    });
    return query as T;
};
/**获取body参数。  也可以直接 await request.json()， 但是这里可以通过泛型得到类型推断 */
export const getBody = async <T extends Record<string, any>>(req: NextRequest): Promise<T> => {
    try {
        return await req.json() as T;
    } catch (error) {
        logError('获取body参数失败', error);
        return Promise.reject('获取body参数失败');
    }
};
/**获取formdata的文件，返回Buffer数组和其它字段的对象
 * @returns [bufferList, otherData]， 如果是文件将会被放入第一个数组中，如果是非文件就会放到第二个元素的对象里
 * @template T 泛型T可以用于返回值的第二个元素的智能提示
 */
export const getFormData = async <T extends Record<string, any> = {}>(req: NextRequest): Promise<[Buffer[], T]> => {
    const formData = await req.formData()
    const bufferList: Buffer[] = []
    const otherData = {} as T
    for (const iterator of formData) {
        const blob = iterator[1]
        if (blob instanceof Blob || iterator[0].includes('file')) {
            const array = await (blob as Blob).arrayBuffer()
            const buffer = Buffer.from(array)
            bufferList.push(buffer)
        } else {
            (otherData as any)[iterator[0]] = iterator[1]
        }
    }
    return [bufferList, otherData] as [Buffer[], T]
}


/**Joi参数校验
 * @param object 要被校验的对象
 * @param rules 校验规则，参加Joi文档 （也就是Joi.object的参数） https://joi.dev/api/?v=17.9.1#introduction
 * @returns 如果成功，返回一个校验后的数据或者空对象  
 */
export const judge = async <T>(object: T, rules: { [key in keyof T]: any }): Promise<T> => {
    try {
        const schema = Joi.object(rules)
        const value = await schema.validateAsync(object);
        return value
    } catch (error) {
        logError('参数校验失败', error)
        return Promise.reject(new RejectData(ResCode.BAD_REQUEST, '参数错误'))
    }
}

/**token鉴权，并判断用户是否有权限。  
 * TODO 涉及到鉴权的时候，这里的函数需要根据实际情况来编写。
 */
export const permissionJudge = async (request: NextRequest, isAdmin = false) => {
    const premiss = await JWT.getTokenAndData(request)
    if (isAdmin /* && !premiss.xxxx */) throw new RejectData(ResCode.FORBIDDEN, '无权访问！')
    return premiss
}
